package com.icss.ah.base.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.net.URL;

import javax.servlet.ServletException;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.multipart.FilePart;
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;

public class FileUtil {
	private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;

	/**
	 * Private constructor to prevent instantiation.
	 *
	 */
	private FileUtil() {
	}

	/**
	 * Compare the contents of two files to determine if they are equal or not.
	 *
	 * @param file1 the first file
	 * @param file2 the second file
	 * @return true if the content of the files are equal or they both don't exist, false otherwise
	 */
	public static boolean contentEquals(final File file1, final File file2)
			throws IOException {
		final boolean file1Exists = file1.exists();
		if (file1Exists != file2.exists()) {
			return false;
		}

		if (!file1Exists) {
			// two not existing files are equal
			return true;
		}

		if (file1.isDirectory() || file2.isDirectory()) {
			// don't want to compare directory contents
			return false;
		}

		InputStream input1 = null;
		InputStream input2 = null;
		try {
			input1 = new FileInputStream(file1);
			input2 = new FileInputStream(file2);
			final InputStream bufferedInput1 = new BufferedInputStream(input1);
			final InputStream bufferedInput2 = new BufferedInputStream(input2);

			int ch = bufferedInput1.read();
			while (ch != -1) {
				if (ch != bufferedInput2.read()) {
					return false;
				}
				ch = bufferedInput1.read();
			}
			if (-1 != bufferedInput2.read()) {
				return false;
			}
			return true;
		} finally {
			shutdownStream(input1);
			shutdownStream(input2);
		}
	}

	/**
	 * Convert from a <code>URL</code> to a <code>File</code>.
	 * @param url File URL.
	 * @return The equivalent <code>File</code> object, or <code>null</code> if the URL's protocol
	 * is not <code>file</code>
	 */
	public static File toFile(final URL url) {
		if (url.getProtocol().equals("file") == false) {
			return null;
		} else {
			final String filename = url.getFile().replace('/',
					File.separatorChar);
			return new File(filename);
		}
	}

	/**
	 * Convert the array of Files into a list of URLs.
	 *
	 * @param files the array of files
	 * @return the array of URLs
	 * @exception IOException if an error occurs
	 */
	public static URL[] toURLs(final File[] files) throws IOException {
		final URL[] urls = new URL[files.length];

		for (int i = 0; i < urls.length; i++) {
			urls[i] = files[i].toURL();
		}

		return urls;
	}

	/**
	 * Remove extension from filename.
	 * ie
	 * <pre>
	 * foo.txt    --> foo
	 * a\b\c.jpg --> a\b\c
	 * a\b\c     --> a\b\c
	 * </pre>
	 *
	 * @param filename the filename
	 * @return the filename minus extension
	 * @deprecated Use removeExtension as removeExtention is mispelled
	 */
	public static String removeExtention(final String filename) {
		return removeExtension(filename);
	}

	/**
	 * Remove extension from filename.
	 * ie
	 * <pre>
	 * foo.txt    --> foo
	 * a\b\c.jpg --> a\b\c
	 * a\b\c     --> a\b\c
	 * </pre>
	 *
	 * @param filename the filename
	 * @return the filename minus extension
	 */
	public static String removeExtension(final String filename) {
		final int index = filename.lastIndexOf('.');

		if (-1 == index) {
			return filename;
		} else {
			return filename.substring(0, index);
		}
	}

	/**
	 * Get extension from filename.
	 * ie
	 * <pre>
	 * foo.txt    --> "txt"
	 * a\b\c.jpg --> "jpg"
	 * a\b\c     --> ""
	 * </pre>
	 *
	 * @param filename the filename
	 * @return the extension of filename or "" if none
	 */
	public static String getExtension(final String filename) {
		final int index = filename.lastIndexOf('.');

		if (-1 == index) {
			return "";
		} else {
			return filename.substring(index + 1);
		}
	}

	/**
	 * Remove path from filename. Equivalent to the unix command <code>basename</code>
	 * ie.
	 * <pre>
	 * a/b/c.txt --> c.txt
	 * a.txt     --> a.txt
	 * </pre>
	 *
	 * @param filepath the filepath
	 * @return the filename minus path
	 */
	public static String removePath(final String filepath) {
		return removePath(filepath, File.separatorChar);
	}

	/**
	 * Remove path from filename.
	 * ie.
	 * <pre>
	 * a/b/c.txt --> c.txt
	 * a.txt     --> a.txt
	 * </pre>
	 *
	 * @param filepath the filepath
	 * @return the filename minus path
	 */
	public static String removePath(final String filepath,
			final char fileSeparatorChar) {
		final int index = filepath.lastIndexOf(fileSeparatorChar);

		if (-1 == index) {
			return filepath;
		} else {
			return filepath.substring(index + 1);
		}
	}

	/**
	 * Get path from filename. Roughly equivalent to the unix command <code>dirname</code>.
	 * ie.
	 * <pre>
	 * a/b/c.txt --> a/b
	 * a.txt     --> ""
	 * </pre>
	 *
	 * @param filepath the filepath
	 * @return the filename minus path
	 */
	public static String getPath(final String filepath) {
		return getPath(filepath, File.separatorChar);
	}

	/**
	 * Get path from filename.
	 * ie.
	 * <pre>
	 * a/b/c.txt --> a/b
	 * a.txt     --> ""
	 * </pre>
	 *
	 * @param filepath the filepath
	 * @return the filename minus path
	 */
	public static String getPath(final String filepath,
			final char fileSeparatorChar) {
		final int index = filepath.lastIndexOf(fileSeparatorChar);
		if (-1 == index) {
			return "";
		} else {
			return filepath.substring(0, index);
		}
	}

	/**
	 * Copy file from source to destination. If <code>destinationDirectory</code> does not exist, it
	 * (and any parent directories) will be created. If a file <code>source</code> in
	 * <code>destinationDirectory</code> exists, it will be overwritten.
	 *
	 * @param source An existing <code>File</code> to copy.
	 * @param destination A directory to copy <code>source</code> into.
	 *
	 * @throws FileNotFoundException if <code>source</code> isn't a normal file.
	 * @throws IllegalArgumentException if <code>destinationDirectory</code> isn't a directory.
	 * @throws IOException if <code>source</code> does not exist, the file in
	 * <code>destinationDirectory</code> cannot be written to, or an IO error occurs during copying.
	 */
	public static void copyFileToDirectory(final String source,
			final String destinationDirectory) throws IOException {
		copyFileToDirectory(new File(source), new File(destinationDirectory));
	}

	public static void copyFileToDirectoryNoPath(final String source,
			final String destinationDirectory) throws IOException {
		copyFileToDirectoryNoPath(new File(source), new File(
				destinationDirectory));
	}

	/**
	 * Copy file from source to destination. If <code>destinationDirectory</code> does not exist, it
	 * (and any parent directories) will be created. If a file <code>source</code> in
	 * <code>destinationDirectory</code> exists, it will be overwritten.
	 *
	 * @param source An existing <code>File</code> to copy.
	 * @param destination A directory to copy <code>source</code> into.
	 *
	 * @throws FileNotFoundException if <code>source</code> isn't a normal file.
	 * @throws IllegalArgumentException if <code>destinationDirectory</code> isn't a directory.
	 * @throws IOException if <code>source</code> does not exist, the file in
	 * <code>destinationDirectory</code> cannot be written to, or an IO error occurs during copying.
	 */
	public static void copyFileToDirectory(final File source,
			final File destinationDirectory) throws IOException {
		if (destinationDirectory.exists()
				&& !destinationDirectory.isDirectory()) {
			throw new IllegalArgumentException("Destination is not a directory");
		}

		copyFile(source, new File(destinationDirectory, source.getName()));
	}

	public static void copyFileToDirectoryNoPath(final File source,
			final File destinationDirectory) throws IOException {
		int idx = source.getName().indexOf(".");
		String fileext = source.getName().substring(idx);
		copyFileNopath(source, destinationDirectory, "1" + fileext);
	}

	public static void copyFileToDirectoryBatchNoPath(final File source,
			final File destinationDirectory, final int num) throws IOException {
		int idx = source.getName().indexOf(".");
		String fileext = source.getName().substring(idx);
		copyFileNopath(source, destinationDirectory, num + fileext);
	}

	/**
	 * Copy file from source to destination. The directories up to <code>destination</code> will be
	 * created if they don't already exist. <code>destination</code> will be overwritten if it
	 * already exists.
	 *
	 * @param source An existing non-directory <code>File</code> to copy bytes from.
	 * @param destination A non-directory <code>File</code> to write bytes to (possibly
	 * overwriting).
	 *
	 * @throws IOException if <code>source</code> does not exist, <code>destination</code> cannot be
	 * written to, or an IO error occurs during copying.
	 *
	 * @throws FileNotFoundException if <code>destination</code> is a directory
	 * (use {@link #copyFileToDirectory}).
	 */
	public static void copyFile(final File source, final File destination)
			throws IOException {
		//check source exists
		if (!source.exists()) {
			final String message = "File " + source + " does not exist";
			throw new IOException(message);
		}

		//does destinations directory exist ?
		if (destination.getParentFile() != null
				&& !destination.getParentFile().exists()) {
			destination.mkdirs();
		}

		//make sure we can write to destination
		if (destination.exists() && !destination.canWrite()) {
			final String message = "Unable to open file " + destination
					+ " for writing.";
			throw new IOException(message);
		}

		final FileInputStream input = new FileInputStream(source);
		final FileOutputStream output = new FileOutputStream(destination);
		copy(input, output);
		shutdownStream(input);
		shutdownStream(output);

		if (source.length() != destination.length()) {
			final String message = "Failed to copy full contents from "
					+ source + " to " + destination;
			throw new IOException(message);
		}
	}

	public static void copyFileNopath(final File source,
			final File destination, String fileName) throws IOException {
		//check source exists
		if (!source.exists()) {
			final String message = "File " + source + " does not exist";
			throw new IOException(message);
		}

		//does destinations directory exist ?
		if (destination.getParentFile() != null
				&& !destination.getParentFile().exists()) {
			destination.mkdirs();
		}

		//make sure we can write to destination
		if (destination.exists() && !destination.canWrite()) {
			final String message = "Unable to open file " + destination
					+ " for writing.";
			throw new IOException(message);
		}

		fcopy(source, destination, fileName);
	}

	/**
	 * Copies bytes from the URL <code>source</code> to a file <code>destination</code>.
	 * The directories up to <code>destination</code> will be created if they don't already exist.
	 * <code>destination</code> will be overwritten if it already exists.
	 *
	 * @param source A <code>URL</code> to copy bytes from.
	 * @param destination A non-directory <code>File</code> to write bytes to (possibly
	 * overwriting).
	 *
	 * @throws IOException if
	 * <ul>
	 *  <li><code>source</code> URL cannot be opened</li>
	 *  <li><code>destination</code> cannot be written to</li>
	 *  <li>an IO error occurs during copying</li>
	 * </ul>
	 */
	public static void copyURLToFile(final URL source, final File destination)
			throws IOException {
		//does destination directory exist ?
		if (destination.getParentFile() != null
				&& !destination.getParentFile().exists()) {
			destination.mkdirs();
		}

		//make sure we can write to destination
		if (destination.exists() && !destination.canWrite()) {
			final String message = "Unable to open file " + destination
					+ " for writing.";
			throw new IOException(message);
		}

		final InputStream input = source.openStream();
		final FileOutputStream output = new FileOutputStream(destination);
		copy(input, output);
		shutdownStream(input);
		shutdownStream(output);
	}

	/**
	 * Normalize a path.
	 * Eliminates "/../" and "/./" in a string. Returns <code>null</code> if the ..'s went past the
	 * root.
	 * Eg:
	 * <pre>
	 * /foo//               -->     /foo/
	 * /foo/./              -->     /foo/
	 * /foo/../bar          -->     /bar
	 * /foo/../bar/         -->     /bar/
	 * /foo/../bar/../baz   -->     /baz
	 * //foo//./bar         -->     /foo/bar
	 * /../                 -->     null
	 * </pre>
	 *
	 * @param path the path to normalize
	 * @return the normalized String, or <code>null</code> if too many ..'s.
	 */
	public static String normalize(final String path) {
		String normalized = path;
		// Resolve occurrences of "//" in the normalized path
		while (true) {
			int index = normalized.indexOf("//");
			if (index < 0)
				break;
			normalized = normalized.substring(0, index)
					+ normalized.substring(index + 1);
		}

		// Resolve occurrences of "/./" in the normalized path
		while (true) {
			int index = normalized.indexOf("/./");
			if (index < 0)
				break;
			normalized = normalized.substring(0, index)
					+ normalized.substring(index + 2);
		}

		// Resolve occurrences of "/../" in the normalized path
		while (true) {
			int index = normalized.indexOf("/../");
			if (index < 0)
				break;
			if (index == 0)
				return null; // Trying to go outside our context
			int index2 = normalized.lastIndexOf('/', index - 1);
			normalized = normalized.substring(0, index2)
					+ normalized.substring(index + 3);
		}

		// Return the normalized path that we have completed
		return normalized;
	}

	/**
	 * Will concatenate 2 paths, dealing with <code>..</code>
	 * <p>Eg.,<br />
	 * <code>/a/b/c</code> + <code>d</code> = <code>/a/b/d</code><br />
	 * <code>/a/b/c</code> + <code>../d</code> = <code>/a/d</code><br />
	 * </p>
	 *
	 * Thieved from Tomcat sources...
	 *
	 * @return The concatenated paths, or null if error occurs
	 */
	public static String catPath(final String lookupPath, final String path) {
		// Cut off the last slash and everything beyond
		int index = lookupPath.lastIndexOf("/");
		String lookup = lookupPath.substring(0, index);
		String pth = path;

		// Deal with .. by chopping dirs off the lookup path
		while (pth.startsWith("../")) {
			if (lookup.length() > 0) {
				index = lookup.lastIndexOf("/");
				lookup = lookup.substring(0, index);
			} else {
				// More ..'s than dirs, return null
				return null;
			}

			index = pth.indexOf("../") + 3;
			pth = pth.substring(index);
		}

		return new StringBuffer(lookup).append("/").append(pth).toString();
	}

	/**
	 * Resolve a file <code>filename</code> to it's canonical form. If <code>filename</code> is
	 * relative (doesn't start with <code>/</code>), it will be resolved relative to
	 * <code>baseFile</code>, otherwise it is treated as a normal root-relative path.
	 *
	 * @param baseFile Where to resolve <code>filename</code> from, if <code>filename</code> is
	 * relative.
	 * @param filename Absolute or relative file path to resolve.
	 * @return The canonical <code>File</code> of <code>filename</code>.
	 */
	public static File resolveFile(final File baseFile, String filename) {
		String filenm = null;
		if ('/' != File.separatorChar) {
			filenm = filename.replace('/', File.separatorChar);
		}

		if ('\\' != File.separatorChar) {
			filenm = filename.replace('\\', File.separatorChar);
		}

		// deal with absolute files
		if (filenm.startsWith(File.separator)) {
			File file = new File(filenm);

			try {
				file = file.getCanonicalFile();
			} catch (final IOException ioe) {
			}

			return file;
		}
		// FIXME: I'm almost certain this // removal is unnecessary, as getAbsoluteFile() strips
		// them. However, I'm not sure about this UNC stuff. (JT)
		final char[] chars = filename.toCharArray();
		final StringBuffer sb = new StringBuffer();

		//remove duplicate file separators in succession - except
		//on win32 at start of filename as UNC filenames can
		//be \\AComputer\AShare\myfile.txt
		int start = 0;
		if ('\\' == File.separatorChar) {
			sb.append(filenm.charAt(0));
			start++;
		}

		for (int i = start; i < chars.length; i++) {
			final boolean doubleSeparator = File.separatorChar == chars[i]
					&& File.separatorChar == chars[i - 1];

			if (!doubleSeparator) {
				sb.append(chars[i]);
			}
		}

		filenm = sb.toString();

		//must be relative
		File file = (new File(baseFile, filenm)).getAbsoluteFile();

		try {
			file = file.getCanonicalFile();
		} catch (final IOException ioe) {
		}

		return file;
	}

	/**
	 * Delete a file. If file is directory delete it and all sub-directories.
	 */
	public static void forceDelete(final String file) throws IOException {
		forceDelete(new File(file));
	}

	/**
	 * Delete a file. If file is directory delete it and all sub-directories.
	 */
	public static void forceDelete(final File file) throws IOException {
		if (file.isDirectory()) {
			deleteDirectory(file);
		} else {
			if (false == file.delete()) {
				final String message = "File " + file
						+ " unable to be deleted.";
				throw new IOException(message);
			}
		}
	}

	/**
	 * Recursively delete a directory.
	 */
	public static void deleteDirectory(final String directory)
			throws IOException {
		deleteDirectory(new File(directory));
	}

	/**
	 * Recursively delete a directory.
	 */
	public static void deleteDirectory(final File directory) throws IOException {
		if (!directory.exists()) {
			return;
		}

		cleanDirectory(directory);
		if (false == directory.delete()) {
			throw new IOException("Directory " + directory
					+ " unable to be deleted.");
		}
	}

	/**
	 * Clean a directory without deleting it.
	 */
	public static void cleanDirectory(final String directory)
			throws IOException {
		cleanDirectory(new File(directory));
	}

	/**
	 * Clean a directory without deleting it.
	 */
	public static void cleanDirectory(final File directory) throws IOException {
		if (!directory.exists()) {
			final String message = directory + " does not exist";
			throw new IllegalArgumentException(message);
		}

		if (!directory.isDirectory()) {
			final String message = directory + " is not a directory";
			throw new IllegalArgumentException(message);
		}

		final File[] files = directory.listFiles();

		for (int i = 0; i < files.length; i++) {
			final File file = files[i];

			FileUtil.forceDelete(file);
		}
	}

	/**
	 * Replace substrings of one string with another string and return altered string.
	 *
	 * @param original input string
	 * @param oldString the substring section to replace
	 * @param newString the new substring replacing old substring section
	 * @return converted string
	 */
	private static String replaceSubString(final String original,
			final String oldString, final String newString) {
		final StringBuffer sb = new StringBuffer();

		int end = original.indexOf(oldString);
		int start = 0;
		final int stringSize = oldString.length();

		while (end != -1) {
			sb.append(original.substring(start, end));
			sb.append(newString);
			start = end + stringSize;
			end = original.indexOf(oldString, start);
		}

		end = original.length();
		sb.append(original.substring(start, end));

		return sb.toString();
	}

	/**
	 * Recursively count size of a directory.
	 *
	 * @return size of directory in bytes.
	 */
	public static long sizeOfDirectory(final String directory) {
		return sizeOfDirectory(new File(directory));
	}

	/**
	 * Recursively count size of a directory.
	 *
	 * @return size of directory in bytes.
	 */
	public static long sizeOfDirectory(final File directory) {
		if (!directory.exists()) {
			final String message = directory + " does not exist";
			throw new IllegalArgumentException(message);
		}

		if (!directory.isDirectory()) {
			final String message = directory + " is not a directory";
			throw new IllegalArgumentException(message);
		}

		long size = 0;

		final File[] files = directory.listFiles();
		for (int i = 0; i < files.length; i++) {
			final File file = files[i];

			if (file.isDirectory()) {
				size += sizeOfDirectory(file);
			} else {
				size += file.length();
			}
		}

		return size;
	}

	/**
	 * Get an unique path file
	 * @param basePath base path
	 * @param subPath sub directory name
	 * @return an unique path file that not exists
	 */
	public static File getUniquePath(String basePath, String subPath) {
		File resultPath = new File(basePath, subPath);
		int counter = 1;
		while (resultPath.exists()) {
			resultPath = new File(basePath, subPath + counter);
			counter++;
		}

		return resultPath;
	}

	/**
	 * Get an unique file
	 * @param dir the path where the file in
	 * @param originFile origin file name
	 * @return an unique file that not exists
	 */
	public static File getUniqueFile(String dir, String originFile) {
		String originFileName = removeExtension(originFile);
		String originFileExt = getExtension(originFile);
		File resultFile = new File(dir, originFile);
		int counter = 1;
		while (resultFile.exists()) {
			resultFile = new File(dir, new StringBuffer(originFileName).append(
					counter).append(".").append(originFileExt).toString());
			counter++;
		}
		return resultFile;
	}

	public static boolean pathCheck(String path) {
		try {
			if (!new File(path).isDirectory()) {
				new File(path).mkdirs();
			}

			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return true;
		}
	}

	/**
	 * Unconditionally close an <code>Reader</code>.
	 * Equivalent to {@link Reader#close()}, except any exceptions will be ignored.
	 *
	 * @param output A (possibly null) Reader
	 */
	public static void shutdownReader(final Reader input) {
		if (null == input) {
			return;
		}

		try {
			input.close();
		} catch (final IOException ioe) {
		}
	}

	/**
	 * Unconditionally close an <code>Writer</code>.
	 * Equivalent to {@link Writer#close()}, except any exceptions will be ignored.
	 *
	 * @param output A (possibly null) Writer
	 */
	public static void shutdownWriter(final Writer output) {
		if (null == output) {
			return;
		}

		try {
			output.close();
		} catch (final IOException ioe) {
		}
	}

	/**
	 * Unconditionally close an <code>OutputStream</code>.
	 * Equivalent to {@link OutputStream#close()}, except any exceptions will be ignored.
	 * @param output A (possibly null) OutputStream
	 */
	public static void shutdownStream(final OutputStream output) {
		if (null == output) {
			return;
		}

		try {
			output.close();
		} catch (final IOException ioe) {
		}
	}

	/**
	 * Unconditionally close an <code>InputStream</code>.
	 * Equivalent to {@link InputStream#close()}, except any exceptions will be ignored.
	 * @param input A (possibly null) InputStream
	 */
	public static void shutdownStream(final InputStream input) {
		if (null == input) {
			return;
		}

		try {
			input.close();
		} catch (final IOException ioe) {
		}
	}

	///////////////////////////////////////////////////////////////
	// Core copy methods
	///////////////////////////////////////////////////////////////

	/**
	 * Copy bytes from an <code>InputStream</code> to an <code>OutputStream</code>.
	 */
	public static void copy(final InputStream input, final OutputStream output)
			throws IOException {
		copy(input, output, DEFAULT_BUFFER_SIZE);
	}

	/**
	 * Copy bytes from an <code>InputStream</code> to an <code>OutputStream</code>.
	 * @param bufferSize Size of internal buffer to use.
	 */
	public static void copy(final InputStream input, final OutputStream output,
			final int bufferSize) throws IOException {
		final byte[] buffer = new byte[bufferSize];
		int n = 0;
		while (-1 != (n = input.read(buffer))) {
			output.write(buffer, 0, n);
		}
	}

	/**
	 * Copy chars from a <code>Reader</code> to a <code>Writer</code>.
	 */
	public static void copy(final Reader input, final Writer output)
			throws IOException {
		copy(input, output, DEFAULT_BUFFER_SIZE);
	}

	/**
	 * Copy chars from a <code>Reader</code> to a <code>Writer</code>.
	 * @param bufferSize Size of internal buffer to use.
	 */
	public static void copy(final Reader input, final Writer output,
			final int bufferSize) throws IOException {
		final char[] buffer = new char[bufferSize];
		int n = 0;
		while (-1 != (n = input.read(buffer))) {
			output.write(buffer, 0, n);
		}
	}

	///////////////////////////////////////////////////////////////
	// Derived copy methods
	// InputStream -> *
	///////////////////////////////////////////////////////////////

	///////////////////////////////////////////////////////////////
	// InputStream -> Writer

	/**
	 * Copy and convert bytes from an <code>InputStream</code> to chars on a
	 * <code>Writer</code>.
	 * The platform's default encoding is used for the byte-to-char conversion.
	 */
	public static void copy(final InputStream input, final Writer output)
			throws IOException {
		copy(input, output, DEFAULT_BUFFER_SIZE);
	}

	/**
	 * Copy and convert bytes from an <code>InputStream</code> to chars on a
	 * <code>Writer</code>.
	 * The platform's default encoding is used for the byte-to-char conversion.
	 * @param bufferSize Size of internal buffer to use.
	 */
	public static void copy(final InputStream input, final Writer output,
			final int bufferSize) throws IOException {
		final InputStreamReader in = new InputStreamReader(input);
		copy(in, output, bufferSize);
	}

	/**
	 * Copy and convert bytes from an <code>InputStream</code> to chars on a
	 * <code>Writer</code>, using the specified encoding.
	 * @param encoding The name of a supported character encoding. See the
	 * <a href="http://www.iana.org/assignments/character-sets">IANA
	 * Charset Registry</a> for a list of valid encoding types.
	 */
	public static void copy(final InputStream input, final Writer output,
			final String encoding) throws IOException {
		final InputStreamReader in = new InputStreamReader(input, encoding);
		copy(in, output);
	}

	/**
	 * Copy and convert bytes from an <code>InputStream</code> to chars on a
	 * <code>Writer</code>, using the specified encoding.
	 * @param encoding The name of a supported character encoding. See the
	 *        <a href="http://www.iana.org/assignments/character-sets">IANA
	 *        Charset Registry</a> for a list of valid encoding types.
	 * @param bufferSize Size of internal buffer to use.
	 */
	public static void copy(final InputStream input, final Writer output,
			final String encoding, final int bufferSize) throws IOException {
		final InputStreamReader in = new InputStreamReader(input, encoding);
		copy(in, output, bufferSize);
	}

	///////////////////////////////////////////////////////////////
	// InputStream -> String

	/**
	 * Get the contents of an <code>InputStream</code> as a String.
	 * The platform's default encoding is used for the byte-to-char conversion.
	 */
	public static String toString(final InputStream input) throws IOException {
		return toString(input, DEFAULT_BUFFER_SIZE);
	}

	/**
	 * Get the contents of an <code>InputStream</code> as a String.
	 * The platform's default encoding is used for the byte-to-char conversion.
	 * @param bufferSize Size of internal buffer to use.
	 */
	public static String toString(final InputStream input, final int bufferSize)
			throws IOException {
		final StringWriter sw = new StringWriter();
		copy(input, sw, bufferSize);
		return sw.toString();
	}

	/**
	 * Get the contents of an <code>InputStream</code> as a String.
	 * @param encoding The name of a supported character encoding. See the
	 *    <a href="http://www.iana.org/assignments/character-sets">IANA
	 *    Charset Registry</a> for a list of valid encoding types.
	 */
	public static String toString(final InputStream input, final String encoding)
			throws IOException {
		return toString(input, encoding, DEFAULT_BUFFER_SIZE);
	}

	/**
	 * Get the contents of an <code>InputStream</code> as a String.
	 * @param encoding The name of a supported character encoding. See the
	 *   <a href="http://www.iana.org/assignments/character-sets">IANA
	 *   Charset Registry</a> for a list of valid encoding types.
	 * @param bufferSize Size of internal buffer to use.
	 */
	public static String toString(final InputStream input,
			final String encoding, final int bufferSize) throws IOException {
		final StringWriter sw = new StringWriter();
		copy(input, sw, encoding, bufferSize);
		return sw.toString();
	}

	///////////////////////////////////////////////////////////////
	// InputStream -> byte[]

	/**
	 * Get the contents of an <code>InputStream</code> as a <code>byte[]</code>.
	 */
	public static byte[] toByteArray(final InputStream input)
			throws IOException {
		return toByteArray(input, DEFAULT_BUFFER_SIZE);
	}

	/**
	 * Get the contents of an <code>InputStream</code> as a <code>byte[]</code>.
	 * @param bufferSize Size of internal buffer to use.
	 */
	public static byte[] toByteArray(final InputStream input,
			final int bufferSize) throws IOException {
		final ByteArrayOutputStream output = new ByteArrayOutputStream();
		copy(input, output, bufferSize);
		return output.toByteArray();
	}

	///////////////////////////////////////////////////////////////
	// Derived copy methods
	// Reader -> *
	///////////////////////////////////////////////////////////////

	///////////////////////////////////////////////////////////////
	// Reader -> OutputStream
	/**
	 * Serialize chars from a <code>Reader</code> to bytes on an <code>OutputStream</code>, and
	 * flush the <code>OutputStream</code>.
	 */
	public static void copy(final Reader input, final OutputStream output)
			throws IOException {
		copy(input, output, DEFAULT_BUFFER_SIZE);
	}

	/**
	 * Serialize chars from a <code>Reader</code> to bytes on an <code>OutputStream</code>, and
	 * flush the <code>OutputStream</code>.
	 * @param bufferSize Size of internal buffer to use.
	 */
	public static void copy(final Reader input, final OutputStream output,
			final int bufferSize) throws IOException {
		final OutputStreamWriter out = new OutputStreamWriter(output);
		copy(input, out, bufferSize);
		// NOTE: Unless anyone is planning on rewriting OutputStreamWriter, we have to flush
		// here.
		out.flush();
	}

	///////////////////////////////////////////////////////////////
	// Reader -> String
	/**
	 * Get the contents of a <code>Reader</code> as a String.
	 */
	public static String toString(final Reader input) throws IOException {
		return toString(input, DEFAULT_BUFFER_SIZE);
	}

	/**
	 * Get the contents of a <code>Reader</code> as a String.
	 * @param bufferSize Size of internal buffer to use.
	 */
	public static String toString(final Reader input, final int bufferSize)
			throws IOException {
		final StringWriter sw = new StringWriter();
		copy(input, sw, bufferSize);
		return sw.toString();
	}

	///////////////////////////////////////////////////////////////
	// Reader -> byte[]
	/**
	 * Get the contents of a <code>Reader</code> as a <code>byte[]</code>.
	 */
	public static byte[] toByteArray(final Reader input) throws IOException {
		return toByteArray(input, DEFAULT_BUFFER_SIZE);
	}

	/**
	 * Get the contents of a <code>Reader</code> as a <code>byte[]</code>.
	 * @param bufferSize Size of internal buffer to use.
	 */
	public static byte[] toByteArray(final Reader input, final int bufferSize)
			throws IOException {
		ByteArrayOutputStream output = new ByteArrayOutputStream();
		copy(input, output, bufferSize);
		return output.toByteArray();
	}

	///////////////////////////////////////////////////////////////
	// Derived copy methods
	// String -> *
	///////////////////////////////////////////////////////////////

	///////////////////////////////////////////////////////////////
	// String -> OutputStream

	/**
	 * Serialize chars from a <code>String</code> to bytes on an <code>OutputStream</code>, and
	 * flush the <code>OutputStream</code>.
	 */
	public static void copy(final String input, final OutputStream output)
			throws IOException {
		copy(input, output, DEFAULT_BUFFER_SIZE);
	}

	/**
	 * Serialize chars from a <code>String</code> to bytes on an <code>OutputStream</code>, and
	 * flush the <code>OutputStream</code>.
	 * @param bufferSize Size of internal buffer to use.
	 */
	public static void copy(final String input, final OutputStream output,
			final int bufferSize) throws IOException {
		final StringReader in = new StringReader(input);
		final OutputStreamWriter out = new OutputStreamWriter(output);
		copy(in, out, bufferSize);
		// NOTE: Unless anyone is planning on rewriting OutputStreamWriter, we have to flush
		// here.
		out.flush();
	}

	///////////////////////////////////////////////////////////////
	// String -> Writer

	/**
	 * Copy chars from a <code>String</code> to a <code>Writer</code>.
	 */
	public static void copy(final String input, final Writer output)
			throws IOException {
		output.write(input);
	}

	/**
	 * Copy bytes from an <code>InputStream</code> to an
	 * <code>OutputStream</code>, with buffering.
	 * This is equivalent to passing a
	 * {@link java.io.BufferedInputStream} and
	 * {@link java.io.BufferedOutputStream} to {@link #copy(InputStream, OutputStream)},
	 * and flushing the output stream afterwards. The streams are not closed
	 * after the copy.
	 * @deprecated Buffering streams is actively harmful! See the class description as to why. Use
	 * {@link #copy(InputStream, OutputStream)} instead.
	 */
	public static void bufferedCopy(final InputStream input,
			final OutputStream output) throws IOException {
		final BufferedInputStream in = new BufferedInputStream(input);
		final BufferedOutputStream out = new BufferedOutputStream(output);
		copy(in, out);
		out.flush();
	}

	///////////////////////////////////////////////////////////////
	// String -> byte[]
	/**
	 * Get the contents of a <code>String</code> as a <code>byte[]</code>.
	 */
	public static byte[] toByteArray(final String input) throws IOException {
		return toByteArray(input, DEFAULT_BUFFER_SIZE);
	}

	/**
	 * Get the contents of a <code>String</code> as a <code>byte[]</code>.
	 * @param bufferSize Size of internal buffer to use.
	 */
	public static byte[] toByteArray(final String input, final int bufferSize)
			throws IOException {
		ByteArrayOutputStream output = new ByteArrayOutputStream();
		copy(input, output, bufferSize);
		return output.toByteArray();
	}

	///////////////////////////////////////////////////////////////
	// Derived copy methods
	// byte[] -> *
	///////////////////////////////////////////////////////////////

	///////////////////////////////////////////////////////////////
	// byte[] -> Writer

	/**
	 * Copy and convert bytes from a <code>byte[]</code> to chars on a
	 * <code>Writer</code>.
	 * The platform's default encoding is used for the byte-to-char conversion.
	 */
	public static void copy(final byte[] input, final Writer output)
			throws IOException {
		copy(input, output, DEFAULT_BUFFER_SIZE);
	}

	/**
	 * Copy and convert bytes from a <code>byte[]</code> to chars on a
	 * <code>Writer</code>.
	 * The platform's default encoding is used for the byte-to-char conversion.
	 * @param bufferSize Size of internal buffer to use.
	 */
	public static void copy(final byte[] input, final Writer output,
			final int bufferSize) throws IOException {
		final ByteArrayInputStream in = new ByteArrayInputStream(input);
		copy(in, output, bufferSize);
	}

	/**
	 * Copy and convert bytes from a <code>byte[]</code> to chars on a
	 * <code>Writer</code>, using the specified encoding.
	 * @param encoding The name of a supported character encoding. See the
	 * <a href="http://www.iana.org/assignments/character-sets">IANA
	 * Charset Registry</a> for a list of valid encoding types.
	 */
	public static void copy(final byte[] input, final Writer output,
			final String encoding) throws IOException {
		final ByteArrayInputStream in = new ByteArrayInputStream(input);
		copy(in, output, encoding);
	}

	/**
	 * Copy and convert bytes from a <code>byte[]</code> to chars on a
	 * <code>Writer</code>, using the specified encoding.
	 * @param encoding The name of a supported character encoding. See the
	 *        <a href="http://www.iana.org/assignments/character-sets">IANA
	 *        Charset Registry</a> for a list of valid encoding types.
	 * @param bufferSize Size of internal buffer to use.
	 */
	public static void copy(final byte[] input, final Writer output,
			final String encoding, final int bufferSize) throws IOException {
		final ByteArrayInputStream in = new ByteArrayInputStream(input);
		copy(in, output, encoding, bufferSize);
	}

	///////////////////////////////////////////////////////////////
	// byte[] -> String

	/**
	 * Get the contents of a <code>byte[]</code> as a String.
	 * The platform's default encoding is used for the byte-to-char conversion.
	 */
	public static String toString(final byte[] input) throws IOException {
		return toString(input, DEFAULT_BUFFER_SIZE);
	}

	/**
	 * Get the contents of a <code>byte[]</code> as a String.
	 * The platform's default encoding is used for the byte-to-char conversion.
	 * @param bufferSize Size of internal buffer to use.
	 */
	public static String toString(final byte[] input, final int bufferSize)
			throws IOException {
		final StringWriter sw = new StringWriter();
		copy(input, sw, bufferSize);
		return sw.toString();
	}

	/**
	 * Get the contents of a <code>byte[]</code> as a String.
	 * @param encoding The name of a supported character encoding. See the
	 *    <a href="http://www.iana.org/assignments/character-sets">IANA
	 *    Charset Registry</a> for a list of valid encoding types.
	 */
	public static String toString(final byte[] input, final String encoding)
			throws IOException {
		return toString(input, encoding, DEFAULT_BUFFER_SIZE);
	}

	/**
	 * Get the contents of a <code>byte[]</code> as a String.
	 * @param encoding The name of a supported character encoding. See the
	 *   <a href="http://www.iana.org/assignments/character-sets">IANA
	 *   Charset Registry</a> for a list of valid encoding types.
	 * @param bufferSize Size of internal buffer to use.
	 */
	public static String toString(final byte[] input, final String encoding,
			final int bufferSize) throws IOException {
		final StringWriter sw = new StringWriter();
		copy(input, sw, encoding, bufferSize);
		return sw.toString();
	}

	///////////////////////////////////////////////////////////////
	// byte[] -> OutputStream

	/**
	 * Copy bytes from a <code>byte[]</code> to an <code>OutputStream</code>.
	 */
	public static void copy(final byte[] input, final OutputStream output)
			throws IOException {
		copy(input, output, DEFAULT_BUFFER_SIZE);
	}

	/**
	 * Copy bytes from a <code>byte[]</code> to an <code>OutputStream</code>.
	 * @param bufferSize Size of internal buffer to use.
	 */
	public static void copy(final byte[] input, final OutputStream output,
			final int bufferSize) throws IOException {
		output.write(input);
	}

	/**
	 * Copy bytes from a <code>File</code> to an <code>File</code>.
	 * @param bufferSize Size of internal buffer to use.
	 */
	public static void copy(final File input, final File output)
			throws IOException {
		FileInputStream fis = new FileInputStream(input);
		FileOutputStream fos = new FileOutputStream(output);
		copy(fis, fos);
		fis.close();
		fos.flush();
		fos.close();
	}

	/**
	 * 将某个目录(srcDir)下的文件、文件夹复制到指定目录(destineDir)中
	 *
	 * @param srcDir 要复制的目录
	 * @param destineDir 要粘帖的目录
	 * @throws IOException
	 */
	public static void xcopy(File srcDir, File destineDir) throws IOException {
		try {
			if (!srcDir.exists()
					|| srcDir.getCanonicalPath().equals(
							destineDir.getCanonicalPath()))
				return;
		} catch (IOException ioexception) {
		}
		if (!destineDir.exists()) {
			destineDir.mkdirs();
		}
		File chs[] = srcDir.listFiles();
		for (int i = 0; i < chs.length; i++) {
			if (chs[i].isFile()) {
				File destineFile = new File(destineDir, chs[i].getName());
				copy(chs[i], destineFile);
			} else {
				File destine = new File(destineDir, chs[i].getName());
				destine.mkdirs();
				xcopy(chs[i], destine);
			}
		}
	}

	public static void fcopy(File src, File destineDir, String FileName)
			throws IOException {
		try {
			if (!src.exists()
					|| src.getCanonicalPath().equals(
							destineDir.getCanonicalPath()))
				return;
		} catch (IOException ioexception) {
		}
		if (!destineDir.exists()) {
			destineDir.mkdirs();
		}
		if (src.isFile()) {
			File destineFile = new File(destineDir, FileName);
			copy(src, destineFile);
		}
	}
	
	/**
	 * 图片上传
	 * @throws IOException
	 * @throws ServletException
	 */
	public static int uploadFileHttp(String newFileName,File file) {
		String uploadImgUrl = ResourceLoader.getInstance("icss").getString("uploadImgUrl");
		int status = 0;
		if (file != null) {
			try {
				// 通过以下方法可以模拟页面参数提交
				Part[] parts = { new FilePart(newFileName, file) };
				PostMethod filePost = new PostMethod(uploadImgUrl);
				filePost.setParameter("newFileName", newFileName);
				filePost.setRequestEntity(new MultipartRequestEntity(parts,
						filePost.getParams()));
				HttpClient client = new HttpClient();
				client.getHttpConnectionManager().getParams()
						.setConnectionTimeout(2000);
				status = client.executeMethod(filePost);
			} catch (Exception ex) {
				ex.printStackTrace();
			}
		}
		/*if (status == HttpStatus.SC_OK) {
			// 上传成功
			System.out.println("上传成功:" + newFileName);
		} else {
			// 上传失败
			System.out.println("上传失败");
		}*/
		return status;
	}
	
}
